home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / clang / stayresc.zip / STAYRES.C < prev    next >
Text File  |  1985-10-27  |  12KB  |  330 lines

  1.  
  2. /****************************************************************************/
  3. /*                                        */
  4. /*     STAYRES.C   Version 1.1    10/26/85           Brian Irvine        */
  5. /*                                        */
  6. /****************************************************************************/
  7. /*                                        */
  8. /* stayres.c - Code which can be used in a general way to create programs   */
  9. /*           in C which will terminate and stay resident.  This code        */
  10. /*           will allow the use of DOS I/O without having the stack and   */
  11. /*           registers clobbered.  This code is written in DeSmet C and   */
  12. /*           uses library functions which may not be available in other   */
  13. /*           C compilers.  It also makes heavy use of the #asm compiler   */
  14. /*           directive to allow in-line assembly language within the C    */
  15. /*           code.  This code provides a general outline for a main()     */
  16. /*           function which can be modified to suit the users needs. All  */
  17. /*           the code necessary to terminate and stay resident is        */
  18. /*           contained in this module; the user's program can be contain- */
  19. /*           ed entirely externally.    The program does not have to be a   */
  20. /*           COM file, and the amount of memory reserved is not limited   */
  21. /*           to 64K. The code has not been tested on program files with   */
  22. /*           greater than 64K of code.                    */
  23. /*                                        */
  24. /*           This code is based on a set of routines written in Turbo     */
  25. /*           Pascal by Lane H. Ferris which are available on the Borland  */
  26. /*           SIG on Compuserve.                        */
  27. /*                                        */
  28. /*           Brian Irvine                            */
  29. /*           3379 St Marys Place                        */
  30. /*           Santa Clara, CA 95051                        */
  31. /*           [71016,544]                            */
  32. /*                                        */
  33. /****************************************************************************/
  34.  
  35.  
  36. /****************************************************************************/
  37. /*                                        */
  38. /* Modification Log:                                */
  39. /*     Version 1.10 - 10/26/85                            */
  40. /*     Corrected error in restoring stack which caused major problems.        */
  41. /*     Tested now with Personal Editor, Volkswriter Deluxe, Crosstalk.        */
  42. /*     Removed redundant code which restored registers twice, once from     */
  43. /*     memory and again from the stack.                     */
  44. /*                                        */
  45. /****************************************************************************/
  46.  
  47. #include   "stdio.h"
  48.  
  49. /*----- Global variables ---------------------------------------------------*/
  50.  
  51. unsigned   dos_regs [10];           /* save DOS registers here */
  52. unsigned   dos_dseg;               /* save the DS and SS regs */
  53. unsigned   dos_sseg;               /* for later convenience */
  54. unsigned   dos_sp;               /* storage for DOS stack pointer */
  55. unsigned   c_sseg;               /* save our stack segment here */
  56. unsigned   c_sp;               /* and our stack pointer here */
  57. unsigned   stacksize;               /* size of DOS/local stack */
  58. int       _rax, _rbx, _rcx, _rdx,     /* variables hold register values */
  59.        _rsi, _rdi, _rds, _res;
  60.  
  61. /*--------------------------------------------------------------------------*/
  62. /* note: storage to save the DOS/C data segments must be allocated in the   */
  63. /*     code segment, so variable must be defined inside "#asm - #" area.  */
  64. /*--------------------------------------------------------------------------*/
  65.  
  66. /*----- Constants ----------------------------------------------------------*/
  67.  
  68. #define    KB_INT      0x16    /* BIOS software int keyboard service routine */
  69. #define    DOS_INT     0x21    /* DOS kitchen sink interrupt */
  70. #define    USER_INT    0x67    /* INT 16H vector is moved to here */
  71.  
  72. #define    WAKEUP      0x71    /* scan code for Alt-F10 */
  73. #define    PARAGRAPHS  0x1000  /* # of paragraphs of memory to keep */
  74.  
  75. /*----- Externals ----------------------------------------------------------*/
  76.  
  77. extern unsigned _PCB;    /* DeSmet C stores original sp value at _PCB + 2. */
  78. extern void    program();           /* user's program module entry point */
  79.  
  80. /*--------------------------------------------------------------------------*/
  81. /*     Initial program startup code                        */
  82. /*--------------------------------------------------------------------------*/
  83.  
  84. main ()
  85. {
  86.  
  87. /* Save the C data segment and reserve storage in code segment for later use */
  88.  
  89. #asm
  90.  
  91.        jmp       get_ds
  92.  
  93. active_:   db       0
  94. c_ds_:       dw       0
  95. dos_ds_:   dw       0
  96.  
  97. get_ds:    push    ax
  98.        mov       ax,ds
  99.        mov       cs:c_ds_,ax
  100.        pop       ax
  101.  
  102. #
  103.    /* initialize program stack segment variable */
  104.  
  105.    c_sseg = _showds();
  106.  
  107.    /* get the current address of INT 16H and save it */
  108.  
  109.    _res = 0;               /* just for DOS 3.0 */
  110.    _rax = 0x3500 + USER_INT;
  111.    _doint (DOS_INT);
  112.  
  113.    if ( _res != 0 )
  114.        puts ("\nInterrupt 67H in use.  Can't install program.\n");
  115.    else
  116.        {
  117.  
  118. /*--------------------------------------------------------------------------*/
  119. /*     Do your program initialization here because you won't get hold of    */
  120. /*     it again until it is entered with the wakeup key sequence.        */
  121. /*--------------------------------------------------------------------------*/
  122.  
  123.        /* get address of current INT 16H routine */
  124.  
  125.        _rax = 0x3500 + KB_INT;
  126.        _doint (DOS_INT);
  127.  
  128.        /* set the old INT 16H code up as INT 67H for later use */
  129.  
  130.        _rax = 0x2500 + USER_INT;
  131.        _rds = _res;
  132.        _rdx = _rbx;
  133.        _doint (DOS_INT);
  134.  
  135.        /*  now set the INT 16H vector to point to our new service routine */
  136.  
  137.        _rax = 0x2500 + KB_INT;
  138.        _rds = _showcs();
  139.  
  140. #asm
  141.        push    bx
  142.        lea       bx, back_door_
  143.        mov       word _rdx_,bx
  144.        pop       bx
  145. #
  146.        _doint (DOS_INT);
  147.  
  148.  
  149.        puts ("Resident program installed.\n");
  150.  
  151.        /* now terminate while staying resident */
  152.  
  153.        _rax = 0x3100;
  154.        _rdx = PARAGRAPHS;
  155.        _doint (DOS_INT);
  156.  
  157.        }
  158.  
  159. }
  160.  
  161.  
  162. /*----- Interrupt 16H service routine --------------------------------------*/
  163. /*                                        */
  164. /*     This function replaces the standard BIOS INT 16H service routine.    */
  165. /*     It is called by DOS and our application program to get the next        */
  166. /*     character from the queue, check the shift status, or just see if     */
  167. /*     there is a character in the queue.  All type 1 and 2 requests are    */
  168. /*     passed through to the original service routine, through a long        */
  169. /*     jump to that address.  Type 0 requests (get the next character)        */
  170. /*     are handled through an INT 67H call to the original service rou-     */
  171. /*     tine.  The character obtained is checked to see if it is the        */
  172. /*     designated wakeup key.  If not, it is passed on to DOS.    If it is,   */
  173. /*     then part of the DOS stack is saved on the local stack, all the        */
  174. /*     processor registers are saved in memory and the program is        */
  175. /*     started up.  The C program environment and registers are estab-        */
  176. /*     lished and the DOS environment is saved for later restoration.        */
  177. /*     Upon return from the user's program, the DOS stack is restored       */
  178. /*     from the data saved on the local stack, bringing DOS back to        */
  179. /*     where it was before the user program was turned on.            */
  180. /*     These operations allow programs to be written in C without having    */
  181. /*     to worry about the resident routines destroying the DOS registers    */
  182. /*     when file I/O is used.  It also allows the use of printf().        */
  183. /*                                        */
  184. /*--------------------------------------------------------------------------*/
  185.  
  186.  
  187.  
  188. void   back_door()
  189. {
  190. /*
  191.    Current stack contents:
  192.            sp -> DOS ip
  193.        sp + 2 -> DOS cs
  194.        sp + 4 -> DOS flags
  195.  
  196.    C function prologue:
  197.        push    bp
  198.        mov       bp,sp
  199. */
  200.  
  201. #asm
  202.        pop       bp               ;toss out the bp from the prologue
  203.        cmp       cs:active_,1        ;if the program is currently active,
  204.        jne       not_on           ;go service the request
  205. ;
  206. ; long jump to F000:E82E
  207. ;
  208.        db       0EAH
  209.        dw       0E82EH
  210.        dw       0F000H
  211. ;
  212. not_on:    cmp       ah,0            ;if this is a character request
  213.        jz       chr_rqst           ;check a little further
  214. ;
  215. ; long jump to F000:E82E
  216. ;
  217.        db       0EAH
  218.        dw       0E82EH
  219.        dw       0F000H
  220. ;
  221. chr_rqst:
  222.        int       67H               ;get the next character from the queue
  223.        cmp       ah,71H           ;if it's not the wakeup character,
  224.        jne       skipall           ;then take it back to the caller
  225.        mov       cs:active_,1        ;else set the 'program active' flag
  226. ;
  227. ;  now we enter the program
  228. ;
  229.        cli                   ;no interrupts for now
  230.        mov       cs:dos_ds_,ds       ;save the DOS data segment
  231.        mov       ds,cs:c_ds_           ;establish our data segment
  232.        push    bp               ;save bp
  233.        mov       bp,offset dos_regs_ ;point to dos_regs
  234.        mov       ds:[bp+0], ax       ;copy the current registers into an
  235.        mov       ds:[bp+2], bx       ;array in the local data segment
  236.        mov       ds:[bp+4], cx
  237.        mov       ds:[bp+6], dx
  238.        pop       ds:[bp+8]           ;get the bp and save it
  239.        mov       ds:[bp+10], si
  240.        mov       ds:[bp+12], di
  241.        push    ax
  242.        mov       ax, cs:dos_ds_      ;save the DOS ds reg
  243.        mov       ds:[bp+14], ax
  244.        pop       ax
  245.        mov       ds:[bp+16], es      ;save es
  246.        pushf               ;save the flags too
  247.        pop       ds:[bp+18]
  248.        mov       word dos_sseg_,ss   ;save DOS stack segment
  249.        mov       si,ss           ;if DOS stack segment and C stack
  250.        mov       es,si           ;segment are the same, then use the
  251.        mov       ss,word c_sseg_     ;current stack pointer for saving
  252.        cmp       si,word c_sseg_     ;the registers. If not the same, then
  253.        mov       si,sp           ;we are entering the program so use
  254.        je       keep_sp           ;the starting stack pointer
  255.        mov       si,ss:_PCB_ + 2
  256. keep_sp:   xchg    sp,si           ;save the registers on the stack
  257.                        ;now using local stack (ds = ss)
  258.        push    [bp+0]           ;save ax
  259.        push    [bp+2]           ;save bx
  260.        push    [bp+4]           ;save cx
  261.        push    [bp+6]           ;save dx
  262.                        ;don't save bp
  263.        push    [bp+10]           ;save si
  264.        push    [bp+12]           ;save di
  265.        push    [bp+14]           ;save ds
  266.        push    [bp+16]           ;save es
  267.                        ;don't save flags
  268.        sub       cx,cx           ;now save 40 words or less from the
  269.        sub       cx,si           ;DOS stack onto the current stack
  270.        shr       cx,1            ;If the stack size is less than 40
  271.        cmp       cx,40           ;save 'stacksize' words, else save 40
  272.        jle       under40
  273.        mov       cx,40
  274. under40:   mov       word stacksize_,cx
  275. restack:   push    es:[si]
  276.        inc       si
  277.        inc       si
  278.        loop    restack
  279.        push    si               ;save the count of words pushed on stack
  280.        mov       word c_sp_,sp       ;save current stack pointer
  281.        sti
  282.        push    bp               ;do the C function prologue here
  283.        mov       bp,sp
  284.  
  285. #
  286.  
  287. /*----- Call your program from here ----------------------------------------*/
  288.  
  289.        program();
  290.  
  291. /*----- Restore everything -------------------------------------------------*/
  292.  
  293. #asm
  294. restore:
  295.        pop       bp
  296.        cli                   ;no interrupts
  297.        mov       sp,word c_sp_       ;get the stack pointer back
  298.        pop       si               ;get pointer to top of words to be moved
  299.        mov       cx,word stacksize_  ;get count of words to move
  300.        mov       es,word dos_sseg_   ;point es to caller's stack
  301. unstack:   dec       si               ;back up one word
  302.        dec       si
  303.        pop       es:[si]           ;restore the caller's stack from
  304.        loop    unstack
  305.        mov       bp,si           ;save pointer to top of caller's stack
  306.        pop       es               ;pop registers off the stack
  307.        pop       di               ;don't restore ds just yet
  308.        pop       di
  309.        pop       si
  310.        pop       dx
  311.        pop       cx
  312.        pop       bx
  313.        pop       ax
  314.        mov       sp,bp           ;restore the caller's stack pointer
  315.        mov       ax,0            ;tell caller there was no character
  316.        mov       ss,word dos_sseg_   ;switch back to the caller's stack
  317.        mov       bp,offset dos_regs_
  318.        push    ds:[bp+18]           ;restore the flags from memory
  319.        popf
  320.        mov       bp,ds:[bp+8]        ;restore the caller's bp reg
  321.        mov       cs:active_,0        ;reset the 'program active' flag
  322.        mov       ds,cs:dos_ds_       ;finally restore caller's data segment
  323. skipall:   iret                ;head on back
  324.  
  325. #
  326.  
  327. }
  328.  
  329.  
  330.